package com.zw.commons.security.filter;/*
 *@program:java-cloud-prevalence
 *@author:zw
 *@Time: 2022/12/10
 *@description: token拦截器
 */

import ch.qos.logback.core.net.SyslogConstants;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.IPUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zw.api.LogFeignClient;
import com.zw.api.SystemFeignClient;
import com.zw.commons.security.custom.CustomUser;
import com.zw.commons.security.utils.ResponseUtil;
import com.zw.commons.utlis.IpUtil;
import com.zw.commons.utlis.JwtHelper;
import com.zw.object.result.Result;
import com.zw.object.result.ResultCodeEnum;
import com.zw.object.system.SysLoginLog;
import com.zw.object.vo.LogLoginVo;
import com.zw.object.vo.LoginVo;
import org.apache.http.auth.AUTH;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ApplicationListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter implements ApplicationListener<AbstractAuthenticationFailureEvent> {

    private RedisTemplate redisTemplate;
    private String username;

    private LogFeignClient logFeignClient;

    public TokenLoginFilter(AuthenticationManager authenticationManager,RedisTemplate redisTemplate,LogFeignClient logFeignClient) {
        this.logFeignClient = logFeignClient;
        this.setAuthenticationManager(authenticationManager);
        this.setPostOnly(false);
        //指定登录接口及提交方式，可以指定任意路径    ->   设置当前登录的路径
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login","POST"));
        this.redisTemplate = redisTemplate;
    }

//    获取用户和密码，进行认证
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        try {
            LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
            Authentication authentication = new UsernamePasswordAuthenticationToken(loginVo.getUsername(),loginVo.getPassword());
            return this.getAuthenticationManager().authenticate(authentication);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

//    认证成功调用
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
//        获取认证的对象
        CustomUser user = (CustomUser) authResult.getPrincipal();
        logger.info(user);
//        生成Token
        String token = JwtHelper.createToken(user.getSysUser().getId(), user.getSysUser().getUsername());
        //保存权限数据
        redisTemplate.opsForValue().set(user.getUsername(), JSON.toJSONString(user.getAuthorities()));
        //        保存成功日志
        LogLoginVo logLoginVo = new LogLoginVo(user.getUsername(),1, IpUtil.getIpAddress(request),"登录成功");
        logFeignClient.AsyncLoginLogSave(logLoginVo);
//        返回
        Map<String, Object> map = new HashMap<>();
        map.put("token",token);
        ResponseUtil.out(response, Result.ok(map));
    }

//    认证失败调用
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response,
                                              AuthenticationException e) throws IOException, ServletException {
        LogLoginVo logLoginVo = new LogLoginVo(this.username==null?this.username:"", 0, IpUtil.getIpAddress(request), "登录失败");
//        logFeignClient.AsyncLoginLogSave(logLoginVo);
        if(e.getCause() instanceof RuntimeException) {
            ResponseUtil.out(response, Result.build(null, 204, e.getMessage()));
        } else {
            ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
        }
    }


    @Override
    public void onApplicationEvent(AbstractAuthenticationFailureEvent event) {
        String  username = (String) event.getAuthentication().getPrincipal();
        this.username = username;
    }
}
